/*
 * fifo_io.c
 *
 * fifo routines
 *
 * Copyright (C) 2020 Long-Horn
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <fcntl.h>
#include <string.h> 
#include <errno.h>

#include "fifo_io.h"

static int open_wr_fifo(const char *fifoname)
{
    int res, fd;
    
    if (access(fifoname, F_OK) < 0) {
        res = mkfifo(fifoname, 0700);
        if(res < 0){
            printf("%s: create %s failed\n", __func__, fifoname);
            return -1;
        }
         printf("%s: create %s successful\n", __func__, fifoname);
    }

    fd = open(fifoname, O_RDWR);
    if(fd < 0){
        printf("%s: open %s failed.\n", __func__, fifoname);
    }

    return fd;
}

static int open_rd_fifo(const char *fifoname)
{
    int fd;
    
    fd = open(fifoname, O_RDWR);
    if(fd < 0){
        printf("%s: open %s failed.\n", __func__, fifoname);
    }

    return fd;
}

static int  fifo_io_isopen(void *fio)
{
    fifo_io_s *pfio = (fifo_io_s *)fio;
    return (pfio->wfd > 0 && pfio->rfd > 0);
}

static int fifo_io_open(void *fio)
{
    fifo_io_s *pfio = (fifo_io_s *)fio;
    if (fifo_io_isopen(pfio))
        return -1;

    pfio->wfd = open_wr_fifo(pfio->wr_fifoname);
    if (pfio->wfd < 0)
        return -1;
    
    printf("%s: rd_fifoname=%s \n", __func__, pfio->rd_fifoname);
    pfio->rfd = open_rd_fifo(pfio->rd_fifoname);
    if (pfio->rfd < 0)
        return -1;
    
    return 0;
}

static void fifo_io_close(void *fio)
{
    fifo_io_s *pfio = (fifo_io_s *)fio;
    if (fifo_io_isopen(pfio)) {
        close(pfio->wfd);
        close(pfio->rfd);
        pfio->wfd = 0;
        pfio->rfd = 0;
    }
}

static int fifo_io_write(void *fio, void *buffer, size_t count)
{
    int written_len;
    
    fifo_io_s *pfio = (fifo_io_s *)fio;
    pthread_mutex_lock(&pfio->write_mutex);
    written_len = write(pfio->wfd, buffer, count);
    pthread_mutex_unlock(&pfio->write_mutex);
    
    return written_len;
}

static int fifo_io_read(void *fio, void *buffer, size_t count)
{
    int read_len;

    fifo_io_s *pfio = (fifo_io_s *)fio;
    
    pthread_mutex_lock(&pfio->read_mutex);
    read_len = read(pfio->rfd, buffer, count);
    pthread_mutex_unlock(&pfio->read_mutex);
    
    return read_len;
}

static int fifo_io_write_timeout(void *fio, void *buffer, size_t count, size_t ms)
{

    return 0;
}

static int fifo_io_read_timeout(void *fio, void *buffer, size_t count, size_t ms)
{
    return 0;
}

static int fifo_io_write_with_response(void *fio, void *buffer, size_t count, void *response)
{

    return 0;
}

int create_fifo_io(fifo_io_s **fio, const char *rd_fifoname, const char *wr_fifoname)
{
    fifo_io_s *p_fio = NULL;
    p_fio = (fifo_io_s *)malloc(sizeof(fifo_io_s));
    if(NULL == p_fio) {
        printf("### %s: malloc fifo_io_s failed!\n", __func__);
        return -1;
    }
    
    pthread_mutex_init(&p_fio->read_mutex, NULL);
    pthread_mutex_init(&p_fio->write_mutex, NULL);
    
    printf("%s: rd_fifoname=%s \n", __func__, rd_fifoname);
    strcpy(p_fio->rd_fifoname, rd_fifoname);
    strcpy(p_fio->wr_fifoname, wr_fifoname);
    
    printf("%s: p_fio->rd_fifoname=%s \n", __func__, p_fio->rd_fifoname);
    
    p_fio->open = fifo_io_open;
    p_fio->close = fifo_io_close;
    p_fio->read = fifo_io_read;
    p_fio->write = fifo_io_write;
    p_fio->read_timeout = fifo_io_read_timeout;
    p_fio->write_timeout = fifo_io_write_timeout;
    p_fio->write_with_response = fifo_io_write_with_response;
    
    p_fio->wfd = 0;
    p_fio->rfd = 0;
    
    *fio = p_fio;
    
    printf("%s: OK!\n", __func__);
    
    return 0;
}

void destroy_fifo_io(fifo_io_s *fio)
{
    fifo_io_s *pfio = (fifo_io_s *)fio;
    if (NULL != pfio) {
        pthread_mutex_destroy(&pfio->read_mutex);
        pthread_mutex_destroy(&pfio->write_mutex);
        
        free(fio);
    }
}

